/*
 * Copyright (c) gitee.com/jiandong001.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { ViewAtIndex } from './ViewAtIndex';
import { ReadableArray } from '../bridge/ReadableArray';
import hilog from '@ohos.hilog';

import { JSResponderHandler } from './JSResponderHandler';
import { StateWrapper } from './StateWrapper';
import { ReactStylesDiffMap } from './ReactStylesDiffMap';
import { ThemedReactContext } from './ThemedReactContext';
import { ReactShadowNode } from './ReactShadowNode';
import { ViewManager } from './ViewManager';
import HashSet from '@ohos.util.LightWeightSet';
import { View } from './View';
import HashMap from '@ohos.util.LightWeightMap';
import { ViewManagerRegistry } from './ViewManagerRegistry'
import { RootViewManager } from './RootViewManager'


type ShadowNodeViewManager = ViewManager<View, ReactShadowNode>
//@NotThreadSafe
export class NativeViewHierarchyManager {
  private static readonly TAG = "NativeViewHierarchyManager";
  //    }
  private DEBUG_MODE: boolean;
  private mTagsToViews: HashMap<number, View> ;
  private mTagsToViewManagers: HashMap<number, ShadowNodeViewManager> ;
  private mRootTags: HashMap<number, boolean> ;
  private mViewManagers: ViewManagerRegistry;
  private mJSResponderHandler: JSResponderHandler;
  //    private final LayoutAnimationController mLayoutAnimator;
  //    private final RectF mBoundingBox;
  //    private boolean mLayoutAnimationEnabled;
  private mRootViewManager: RootViewManager ;

  //    public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
  //        this(viewManagers, new RootViewManager());
  //    private PopupMenu mPopupMenu;
  private mPendingDeletionsForTag: HashMap<number, HashSet<number>> ;

  public constructor(viewManagers: ViewManagerRegistry, manager: RootViewManager) {
    //        if (ReactBuildConfig.DEBUG) {
    //        }

    this.DEBUG_MODE = false;
    this.mJSResponderHandler = new JSResponderHandler();
    //        this.mLayoutAnimator = new LayoutAnimationController();
    //        this.mBoundingBox = new RectF();
    this.mViewManagers = viewManagers;
    this.mTagsToViews = new HashMap<number, View>();
    this.mTagsToViewManagers = new HashMap<number, ShadowNodeViewManager>();
    this.mRootTags = new HashMap<number, boolean>();
    this.mRootViewManager = manager;
  }

  // synchronized
  public resolveView(tag: number): View {
    let view = this.mTagsToViews.get(tag) as View;
    if (view == null) {
      throw new Error("Trying to resolve view with tag " + tag + " which doesn't exist");
    } else {
      return view;
    }
  }

  // synchronized
  public resolveViewManager(tag: number): ShadowNodeViewManager {
    let shadowNodeViewManager = this.mTagsToViewManagers.get(tag) as ShadowNodeViewManager
    if (shadowNodeViewManager == null) {
      throw new Error("ViewManager for tag " + tag + " could not be found.\n");
    } else {
      return shadowNodeViewManager;
    }
  }
  //
  //    public void setLayoutAnimationEnabled(boolean enabled) {
  //        this.mLayoutAnimationEnabled = enabled;
  //    }

  //    public synchronized void updateInstanceHandle(int tag, long instanceHandle) {
  //        UiThreadUtil.assertOnUiThread();
  //
  //        try {
  //            this.updateInstanceHandle(this.resolveView(tag), instanceHandle);
  //        } catch (IllegalViewOperationException var5) {
  //            FLog.e(TAG, "Unable to update properties for view tag " + tag, var5);
  //        }
  //
  //    }

  // synchronized
  public updateProperties(tag: number, props: ReactStylesDiffMap) {
    //        if (this.DEBUG_MODE) {
    //            FLog.d(TAG, "updateProperties[%d]: %s", tag, props.toString());
    //        }

    //        UiThreadUtil.assertOnUiThread();

    try {
      let viewManager = this.resolveViewManager(tag);
      let viewToUpdate = this.resolveView(tag);
      if (props != null) {
        viewManager.updateProperties(viewToUpdate, props);
      }
    } catch (var5: any) {
      hilog.info(0x0000, NativeViewHierarchyManager.TAG, '%{public}s', 'Unable to update properties for view tag {View }');
    }

  }

  //synchronized
  public updateViewExtraData(tag: number, extraData: any) {
    if (this.DEBUG_MODE) {
      hilog.info(0x0000, NativeViewHierarchyManager.TAG, '%{public}s', 'updateViewExtraData');
    }

    //        UiThreadUtil.assertOnUiThread();
    let viewManager = this.resolveViewManager(tag);
    let viewToUpdate: View = this.resolveView(tag);
    viewManager.updateExtraData(viewToUpdate, extraData);
  }
  //synchronized
  public updateLayout(parentTag: number, tag: number, x: number, y: number, width: number, height: number) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "updateLayout[%d]->[%d]: %d %d %d %d", new Object[]{tag, parentTag, x, y, width, height});
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        SystraceMessage.beginSection(0L, "NativeViewHierarchyManager_updateLayout").arg("parentTag", parentTag).arg("tag", tag).flush();
  //
  //        try {
  //            View viewToUpdate = this.resolveView(tag);
  //            viewToUpdate.measure(MeasureSpec.makeMeasureSpec(width, 1073741824), MeasureSpec.makeMeasureSpec(height, 1073741824));
  //            ViewParent parent = viewToUpdate.getParent();
  //            if (parent instanceof RootView) {
  //                parent.requestLayout();
  //            }
  //
  //            if (!this.mRootTags.get(parentTag)) {
  //                ViewManager parentViewManager = (ViewManager)this.mTagsToViewManagers.get(parentTag);
  //                if (!(parentViewManager instanceof IViewManagerWithChildren)) {
  //                    throw new IllegalViewOperationException("Trying to use view with tag " + parentTag + " as a parent, but its Manager doesn't implement IViewManagerWithChildren");
  //                }
  //
  //                IViewManagerWithChildren parentViewManagerWithChildren = (IViewManagerWithChildren)parentViewManager;
  //                if (parentViewManagerWithChildren != null && !parentViewManagerWithChildren.needsCustomLayoutForChildren()) {
  //                    this.updateLayout(viewToUpdate, x, y, width, height);
  //                }
  //            } else {
  //                this.updateLayout(viewToUpdate, x, y, width, height);
  //            }
  //        } finally {
  //            Systrace.endSection(0L);
  //        }
  //
  }
  //
  //    private void updateInstanceHandle(View viewToUpdate, long instanceHandle) {
  //        UiThreadUtil.assertOnUiThread();
  //        viewToUpdate.setTag(id.view_tag_instance_handle, instanceHandle);
  //    }
  //
  //    @Nullable
  //    public long getInstanceHandle(int reactTag) {
  //        View view = (View)this.mTagsToViews.get(reactTag);
  //        if (view == null) {
  //            throw new IllegalViewOperationException("Unable to find view for tag: " + reactTag);
  //        } else {
  //            Long instanceHandle = (Long)view.getTag(id.view_tag_instance_handle);
  //            if (instanceHandle == null) {
  //                throw new IllegalViewOperationException("Unable to find instanceHandle for tag: " + reactTag);
  //            } else {
  //                return instanceHandle;
  //            }
  //        }
  //    }
  //
  //    private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
  //        if (this.mLayoutAnimationEnabled && this.mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
  //            this.mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
  //        } else {
  //            viewToUpdate.layout(x, y, x + width, y + height);
  //        }
  //
  //    }
  // synchronized
  public createView(themedContext: ThemedReactContext, tag: number, className: string, initialProps?: ReactStylesDiffMap): void {
    //        if (this.DEBUG_MODE) {
    //            FLog.d(TAG, "createView[%d]: %s %s", tag, className, initialProps != null ? initialProps.toString() : "<null>");
    //        }

    //        UiThreadUtil.assertOnUiThread();
    //        SystraceMessage.beginSection(0L, "NativeViewHierarchyManager_createView").arg("tag", tag).arg("className", className).flush();

    try {
      let viewManager = this.mViewManagers.get(className) as ShadowNodeViewManager;
      let view: View = viewManager.createView(tag, themedContext, initialProps, null, this.mJSResponderHandler);
      this.mTagsToViews.set(tag, view);
      this.mTagsToViewManagers.set(tag, viewManager);
    } finally {
      //            Systrace.endSection(0L);
    }

  }

  //    private static String constructManageChildrenErrorMessage(ViewGroup viewToManage, ViewGroupManager viewManager, @Nullable int[] indicesToRemove, @Nullable ViewAtIndex[] viewsToAdd, @Nullable int[] tagsToDelete) {
  //        StringBuilder stringBuilder = new StringBuilder();
  //        int index;
  //        int innerOffset;
  //        if (null != viewToManage) {
  //            stringBuilder.append("View tag:" + viewToManage.getId() + " View Type:" + viewToManage.getClass().toString() + "\n");
  //            stringBuilder.append("  children(" + viewManager.getChildCount(viewToManage) + "): [\n");
  //
  //            for(index = 0; viewManager.getChildAt(viewToManage, index) != null; index += 16) {
  //                for(innerOffset = 0; viewManager.getChildAt(viewToManage, index + innerOffset) != null && innerOffset < 16; ++innerOffset) {
  //                    stringBuilder.append(viewManager.getChildAt(viewToManage, index + innerOffset).getId() + ",");
  //                }
  //
  //                stringBuilder.append("\n");
  //            }
  //
  //            stringBuilder.append(" ],\n");
  //        }
  //
  //        if (indicesToRemove != null) {
  //            stringBuilder.append("  indicesToRemove(" + indicesToRemove.length + "): [\n");
  //
  //            for(index = 0; index < indicesToRemove.length; index += 16) {
  //                for(innerOffset = 0; index + innerOffset < indicesToRemove.length && innerOffset < 16; ++innerOffset) {
  //                    stringBuilder.append(indicesToRemove[index + innerOffset] + ",");
  //                }
  //
  //                stringBuilder.append("\n");
  //            }
  //
  //            stringBuilder.append(" ],\n");
  //        }
  //
  //        if (viewsToAdd != null) {
  //            stringBuilder.append("  viewsToAdd(" + viewsToAdd.length + "): [\n");
  //
  //            for(index = 0; index < viewsToAdd.length; index += 16) {
  //                for(innerOffset = 0; index + innerOffset < viewsToAdd.length && innerOffset < 16; ++innerOffset) {
  //                    stringBuilder.append("[" + viewsToAdd[index + innerOffset].mIndex + "," + viewsToAdd[index + innerOffset].mTag + "],");
  //                }
  //
  //                stringBuilder.append("\n");
  //            }
  //
  //            stringBuilder.append(" ],\n");
  //        }
  //
  //        if (tagsToDelete != null) {
  //            stringBuilder.append("  tagsToDelete(" + tagsToDelete.length + "): [\n");
  //
  //            for(index = 0; index < tagsToDelete.length; index += 16) {
  //                for(innerOffset = 0; index + innerOffset < tagsToDelete.length && innerOffset < 16; ++innerOffset) {
  //                    stringBuilder.append(tagsToDelete[index + innerOffset] + ",");
  //                }
  //
  //                stringBuilder.append("\n");
  //            }
  //
  //            stringBuilder.append(" ]\n");
  //        }
  //
  //        return stringBuilder.toString();
  //    }
  //
  //    private Set<Integer> getPendingDeletionsForTag(int tag) {
  //        if (this.mPendingDeletionsForTag == null) {
  //            this.mPendingDeletionsForTag = new HashMap();
  //        }
  //
  //        if (!this.mPendingDeletionsForTag.containsKey(tag)) {
  //            this.mPendingDeletionsForTag.put(tag, new HashSet());
  //        }
  //
  //        return (Set)this.mPendingDeletionsForTag.get(tag);
  //    }
  //
      // synchronized
  public manageChildren(tag: number, indicesToRemove?: number[], viewsToAdd?: ViewAtIndex[], tagsToDelete?: number[]) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "createView[%d]: %s %s %s", tag, indicesToRemove != null ? indicesToRemove.toString() : "<null>", viewsToAdd != null ? viewsToAdd.toString() : "<null>", tagsToDelete != null ? tagsToDelete.toString() : "<null>");
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        final Set<Integer> pendingDeletionTags = this.getPendingDeletionsForTag(tag);
  //        final ViewGroup viewToManage = (ViewGroup)this.mTagsToViews.get(tag);
  //        final ViewGroupManager viewManager = (ViewGroupManager)this.resolveViewManager(tag);
  //        if (viewToManage == null) {
  //            throw new IllegalViewOperationException("Trying to manageChildren view with tag " + tag + " which doesn't exist\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //        } else {
  //            int lastIndexToRemove = viewManager.getChildCount(viewToManage);
  //            int i;
  //            int indexToRemove;
  //            final View viewToAdd;
  //            if (indicesToRemove != null) {
  //                for(i = indicesToRemove.length - 1; i >= 0; --i) {
  //                    indexToRemove = indicesToRemove[i];
  //                    if (indexToRemove < 0) {
  //                        throw new IllegalViewOperationException("Trying to remove a negative view index:" + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //                    }
  //
  //                    if (viewManager.getChildAt(viewToManage, indexToRemove) == null) {
  //                        if (this.mRootTags.get(tag) && viewManager.getChildCount(viewToManage) == 0) {
  //                            return;
  //                        } else {
  //                            throw new IllegalViewOperationException("Trying to remove a view index above child count " + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //                        }
  //                    }
  //
  //                    if (indexToRemove >= lastIndexToRemove) {
  //                        throw new IllegalViewOperationException("Trying to remove an out of order view index:" + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //                    }
  //
  //                    viewToAdd = viewManager.getChildAt(viewToManage, indexToRemove);
  //                    if (!this.mLayoutAnimationEnabled || !this.mLayoutAnimator.shouldAnimateLayout(viewToAdd) || !this.arrayContains(tagsToDelete, viewToAdd.getId())) {
  //                        viewManager.removeViewAt(viewToManage, indexToRemove);
  //                    }
  //
  //                    lastIndexToRemove = indexToRemove;
  //                }
  //            }
  //
  //            if (tagsToDelete != null) {
  //                for(i = 0; i < tagsToDelete.length; ++i) {
  //                    indexToRemove = tagsToDelete[i];
  //                    viewToAdd = (View)this.mTagsToViews.get(indexToRemove);
  //                    if (viewToAdd == null) {
  //                        throw new IllegalViewOperationException("Trying to destroy unknown view tag: " + indexToRemove + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //                    }
  //
  //                    if (this.mLayoutAnimationEnabled && this.mLayoutAnimator.shouldAnimateLayout(viewToAdd)) {
  //                        pendingDeletionTags.add(indexToRemove);
  //                        this.mLayoutAnimator.deleteView(viewToAdd, new LayoutAnimationListener() {
  //                            public void onAnimationEnd() {
  //                                UiThreadUtil.assertOnUiThread();
  //                                viewManager.removeView(viewToManage, viewToAdd);
  //                                NativeViewHierarchyManager.this.dropView(viewToAdd);
  //                                pendingDeletionTags.remove(viewToAdd.getId());
  //                                if (pendingDeletionTags.isEmpty()) {
  //                                    NativeViewHierarchyManager.this.mPendingDeletionsForTag.remove(tag);
  //                                }
  //
  //                            }
  //                        });
  //                    } else {
  //                        this.dropView(viewToAdd);
  //                    }
  //                }
  //            }
  //
  //            if (viewsToAdd != null) {
  //                for(i = 0; i < viewsToAdd.length; ++i) {
  //                    ViewAtIndex viewAtIndex = viewsToAdd[i];
  //                    viewToAdd = (View)this.mTagsToViews.get(viewAtIndex.mTag);
  //                    if (viewToAdd == null) {
  //                        throw new IllegalViewOperationException("Trying to add unknown view tag: " + viewAtIndex.mTag + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
  //                    }
  //
  //                    int normalizedIndex = viewAtIndex.mIndex;
  //                    if (!pendingDeletionTags.isEmpty()) {
  //                        normalizedIndex = 0;
  //
  //                        for(int counter = 0; normalizedIndex < viewToManage.getChildCount() && counter != viewAtIndex.mIndex; ++normalizedIndex) {
  //                            View v = viewToManage.getChildAt(normalizedIndex);
  //                            if (!pendingDeletionTags.contains(v.getId())) {
  //                                ++counter;
  //                            }
  //                        }
  //                    }
  //
  //                    viewManager.addView(viewToManage, viewToAdd, normalizedIndex);
  //                }
  //            }
  //
  //            if (pendingDeletionTags.isEmpty()) {
  //                this.mPendingDeletionsForTag.remove(tag);
  //            }
  //
  //        }
      }
  //
  //    private boolean arrayContains(@Nullable int[] array, int ele) {
  //        if (array == null) {
  //            return false;
  //        } else {
  //            int[] var3 = array;
  //            int var4 = array.length;
  //
  //            for(int var5 = 0; var5 < var4; ++var5) {
  //                int curEle = var3[var5];
  //                if (curEle == ele) {
  //                    return true;
  //                }
  //            }
  //
  //            return false;
  //        }
  //    }
  //
  //    private static String constructSetChildrenErrorMessage(ViewGroup viewToManage, ViewGroupManager viewManager, ReadableArray childrenTags) {
  //        ViewAtIndex[] viewsToAdd = new ViewAtIndex[childrenTags.size()];
  //
  //        for(int i = 0; i < childrenTags.size(); ++i) {
  //            viewsToAdd[i] = new ViewAtIndex(childrenTags.getInt(i), i);
  //        }
  //
  //        return constructManageChildrenErrorMessage(viewToManage, viewManager, (int[])null, viewsToAdd, (int[])null);
  //    }
  //
      //synchronized
      public setChildren(tag: number, childrenTags: ReadableArray) {
          if (this.DEBUG_MODE) {
              hilog.info(0x0, NativeViewHierarchyManager.TAG, "setChildren[%d]: %{public}s", tag, childrenTags != null ? childrenTags.toString() : "<null>");
          }

//          UiThreadUtil.assertOnUiThread();
//          let viewToManage: ViewGroup = (ViewGroup)this.mTagsToViews.get(tag);
//          let viewManager: ViewGroupManager = (ViewGroupManager)this.resolveViewManager(tag);
//
//          for(let i = 0; i < childrenTags.size(); ++i) {
//              let viewToAdd: View = (View)this.mTagsToViews.get(childrenTags.getInt(i));
//              if (viewToAdd == null) {
//                  // throw new Error("Trying to add unknown view tag: " + childrenTags.getInt(i) + "\n detail: " + this.constructSetChildrenErrorMessage(viewToManage, viewManager, childrenTags));
//              }
//
//              viewManager.addView(viewToManage, viewToAdd, i);
//          }

      }
  //
  /*synchronized*/
   public addRootView(tag: number, view: View) {
    this.addRootViewGroup(tag, view);
  }

  // synchronized
  public removeRootView(rootViewTag: number) {
    //        if (this.DEBUG_MODE) {
    //            FLog.d(TAG, "removeRootView[%d]", rootViewTag);
    //        }
    //
    //        UiThreadUtil.assertOnUiThread();
    if (!this.mRootTags.get(rootViewTag)) {
      throw Error("View with tag " + rootViewTag + " is not registered as a root view");
    }

    let rootView: View = this.mTagsToViews.get(rootViewTag) as View;
    this.dropView(rootView);
    this.mRootTags.remove(rootViewTag);
  }
  //

  //
  protected /*final synchronized*/
  addRootViewGroup(tag: number, view: View) {
    if (this.DEBUG_MODE) {
      hilog.debug(0x0, NativeViewHierarchyManager.TAG, "addRootViewGroup['%{public}d']: '%{public}s'", tag, view != null ? view.toString() : "<null>");
    }

    if (view.getId() != -1) {
      hilog.error(0x0, NativeViewHierarchyManager.TAG, "Trying to add a root view with an explicit id (" + view.getId() + ") already set. React Native uses the id field to track react tags and will overwrite this field. If that is fine, explicitly overwrite the id field to View.NO_ID before calling addRootView.");
    }

    this.mTagsToViews.set(tag, view);
    this.mTagsToViewManagers.set(tag, this.mRootViewManager);
    this.mRootTags.set(tag, true);
    view.setId(tag);
  }

  // synchronized
  protected dropView(view: View): void {
    //        if (this.DEBUG_MODE) {
    //            FLog.d(TAG, "dropView[%d]", view != null ? view.getId() : -1);
    //        }

    //        UiThreadUtil.assertOnUiThread();
    if (view != null) {
      //            if (this.mTagsToViewManagers.get(view.getId()) != null) {
      //                if (!this.mRootTags.get(view.getId())) {
      //                    this.resolveViewManager(view.getId()).onDropViewInstance(view);
      //                }
      //
      //                ViewManager viewManager = (ViewManager)this.mTagsToViewManagers.get(view.getId());
      //                if (view instanceof ViewGroup && viewManager instanceof ViewGroupManager) {
      //                    ViewGroup viewGroup = (ViewGroup)view;
      //                    ViewGroupManager viewGroupManager = (ViewGroupManager)viewManager;
      //
      //                    for(int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; --i) {
      //                        View child = viewGroupManager.getChildAt(viewGroup, i);
      //                        if (child == null) {
      //                            FLog.e(TAG, "Unable to drop null child view");
      //                        } else if (this.mTagsToViews.get(child.getId()) != null) {
      //                            this.dropView(child);
      //                        }
      //                    }
      //
      //                    viewGroupManager.removeAllViews(viewGroup);
      //                }
      //
      //                this.mTagsToViews.remove(view.getId());
      //                this.mTagsToViewManagers.remove(view.getId());
    }
  }
  //
  //    public synchronized void measure(int tag, int[] outputBuffer) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "measure[%d]", tag);
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        View v = (View)this.mTagsToViews.get(tag);
  //        if (v == null) {
  //            throw new NoSuchNativeViewException("No native view for " + tag + " currently exists");
  //        } else {
  //            View rootView = (View)RootViewUtil.getRootView(v);
  //            if (rootView == null) {
  //                throw new NoSuchNativeViewException("Native view " + tag + " is no longer on screen");
  //            } else {
  //                this.computeBoundingBox(rootView, outputBuffer);
  //                int rootX = outputBuffer[0];
  //                int rootY = outputBuffer[1];
  //                this.computeBoundingBox(v, outputBuffer);
  //                outputBuffer[0] -= rootX;
  //                outputBuffer[1] -= rootY;
  //            }
  //        }
  //    }
  //
  //    private void computeBoundingBox(View view, int[] outputBuffer) {
  //        this.mBoundingBox.set(0.0F, 0.0F, (float)view.getWidth(), (float)view.getHeight());
  //        this.mapRectFromViewToWindowCoords(view, this.mBoundingBox);
  //        outputBuffer[0] = Math.round(this.mBoundingBox.left);
  //        outputBuffer[1] = Math.round(this.mBoundingBox.top);
  //        outputBuffer[2] = Math.round(this.mBoundingBox.right - this.mBoundingBox.left);
  //        outputBuffer[3] = Math.round(this.mBoundingBox.bottom - this.mBoundingBox.top);
  //    }
  //
  //    private void mapRectFromViewToWindowCoords(View view, RectF rect) {
  //        Matrix matrix = view.getMatrix();
  //        if (!matrix.isIdentity()) {
  //            matrix.mapRect(rect);
  //        }
  //
  //        rect.offset((float)view.getLeft(), (float)view.getTop());
  //
  //        View parentView;
  //        for(ViewParent parent = view.getParent(); parent instanceof View; parent = parentView.getParent()) {
  //            parentView = (View)parent;
  //            rect.offset((float)(-parentView.getScrollX()), (float)(-parentView.getScrollY()));
  //            matrix = parentView.getMatrix();
  //            if (!matrix.isIdentity()) {
  //                matrix.mapRect(rect);
  //            }
  //
  //            rect.offset((float)parentView.getLeft(), (float)parentView.getTop());
  //        }
  //
  //    }
  //
  //    public synchronized void measureInWindow(int tag, int[] outputBuffer) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "measureInWindow[%d]", tag);
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        View v = (View)this.mTagsToViews.get(tag);
  //        if (v == null) {
  //            throw new NoSuchNativeViewException("No native view for " + tag + " currently exists");
  //        } else {
  //            v.getLocationOnScreen(outputBuffer);
  //            Rect visibleWindowFrame = new Rect();
  //            v.getWindowVisibleDisplayFrame(visibleWindowFrame);
  //            outputBuffer[0] -= visibleWindowFrame.left;
  //            outputBuffer[1] -= visibleWindowFrame.top;
  //            outputBuffer[2] = v.getWidth();
  //            outputBuffer[3] = v.getHeight();
  //        }
  //    }
  //
  //    public synchronized int findTargetTagForTouch(int reactTag, float touchX, float touchY) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "findTargetTagForTouch[%d]: %f %f", reactTag, touchX, touchY);
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        View view = (View)this.mTagsToViews.get(reactTag);
  //        if (view == null) {
  //            throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
  //        } else {
  //            return TouchTargetHelper.findTargetTagForTouch(touchX, touchY, (ViewGroup)view);
  //        }
  //    }
  //
  //    public synchronized void setJSResponder(int reactTag, int initialReactTag, boolean blockNativeResponder) {
  //        if (!blockNativeResponder) {
  //            this.mJSResponderHandler.setJSResponder(initialReactTag, (ViewParent)null);
  //        } else {
  //            View view = (View)this.mTagsToViews.get(reactTag);
  //            if (initialReactTag != reactTag && view instanceof ViewParent) {
  //                this.mJSResponderHandler.setJSResponder(initialReactTag, (ViewParent)view);
  //            } else {
  //                if (this.mRootTags.get(reactTag)) {
  //                    SoftAssertions.assertUnreachable("Cannot block native responder on " + reactTag + " that is a root view");
  //                }
  //
  //                this.mJSResponderHandler.setJSResponder(initialReactTag, view.getParent());
  //            }
  //        }
  //    }
  //
  //    public void clearJSResponder() {
  //        this.mJSResponderHandler.clearJSResponder();
  //    }
  //
  //    void configureLayoutAnimation(ReadableMap config, Callback onAnimationComplete) {
  //        this.mLayoutAnimator.initializeFromConfig(config, onAnimationComplete);
  //    }
  //
  //    void clearLayoutAnimation() {
  //        this.mLayoutAnimator.reset();
  //    }
  //
  //    /** @deprecated */
  //    @Deprecated
  //    public synchronized void dispatchCommand(int reactTag, int commandId, @Nullable ReadableArray args) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "dispatchCommand[%d]: %d %s", reactTag, commandId, args != null ? args.toString() : "<null>");
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        View view = (View)this.mTagsToViews.get(reactTag);
  //        if (view == null) {
  //            throw new RetryableMountingLayerException("Trying to send command to a non-existing view with tag [" + reactTag + "] and command " + commandId);
  //        } else {
  //            ViewManager viewManager = this.resolveViewManager(reactTag);
  //            viewManager.receiveCommand(view, commandId, args);
  //        }
  //    }
  //
  //    public synchronized void dispatchCommand(int reactTag, String commandId, @Nullable ReadableArray args) {
  //        if (this.DEBUG_MODE) {
  //            FLog.d(TAG, "dispatchCommand[%d]: %s %s", reactTag, commandId, args != null ? args.toString() : "<null>");
  //        }
  //
  //        UiThreadUtil.assertOnUiThread();
  //        View view = (View)this.mTagsToViews.get(reactTag);
  //        if (view == null) {
  //            throw new RetryableMountingLayerException("Trying to send command to a non-existing view with tag [" + reactTag + "] and command " + commandId);
  //        } else {
  //            ViewManager viewManager = this.resolveViewManager(reactTag);
  //            ViewManagerDelegate delegate = viewManager.getDelegate();
  //            if (delegate != null) {
  //                delegate.receiveCommand(view, commandId, args);
  //            } else {
  //                viewManager.receiveCommand(view, commandId, args);
  //            }
  //
  //        }
  //    }
  //
  //    public synchronized void showPopupMenu(int reactTag, ReadableArray items, Callback success, Callback error) {
  //        UiThreadUtil.assertOnUiThread();
  //        View anchor = (View)this.mTagsToViews.get(reactTag);
  //        if (anchor == null) {
  //            error.invoke(new Object[]{"Can't display popup. Could not find view with tag " + reactTag});
  //        } else {
  //            this.mPopupMenu = new PopupMenu(this.getReactContextForView(reactTag), anchor);
  //            Menu menu = this.mPopupMenu.getMenu();
  //
  //            for(int i = 0; i < items.size(); ++i) {
  //                menu.add(0, 0, i, items.getString(i));
  //            }
  //
  //            NativeViewHierarchyManager.PopupMenuCallbackHandler handler = new NativeViewHierarchyManager.PopupMenuCallbackHandler(success);
  //            this.mPopupMenu.setOnMenuItemClickListener(handler);
  //            this.mPopupMenu.setOnDismissListener(handler);
  //            this.mPopupMenu.show();
  //        }
  //    }
  //
  //    public void dismissPopupMenu() {
  //        if (this.mPopupMenu != null) {
  //            this.mPopupMenu.dismiss();
  //        }
  //
  //    }
  //
  //    private ThemedReactContext getReactContextForView(int reactTag) {
  //        View view = (View)this.mTagsToViews.get(reactTag);
  //        if (view == null) {
  //            throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
  //        } else {
  //            return (ThemedReactContext)view.getContext();
  //        }
  //    }
  //
  //    public void sendAccessibilityEvent(int tag, int eventType) {
  //        View view = (View)this.mTagsToViews.get(tag);
  //        if (view == null) {
  //            throw new JSApplicationIllegalArgumentException("Could not find view with tag " + tag);
  //        } else {
  //            view.sendAccessibilityEvent(eventType);
  //        }
  //    }
  //
  //    private static class PopupMenuCallbackHandler implements OnMenuItemClickListener, OnDismissListener {
  //        final Callback mSuccess;
  //        boolean mConsumed;
  //
  //        private PopupMenuCallbackHandler(Callback success) {
  //            this.mConsumed = false;
  //            this.mSuccess = success;
  //        }
  //
  //        public void onDismiss(PopupMenu menu) {
  //            if (!this.mConsumed) {
  //                this.mSuccess.invoke(new Object[]{"dismissed"});
  //                this.mConsumed = true;
  //            }
  //
  //        }
  //
  //        public boolean onMenuItemClick(MenuItem item) {
  //            if (!this.mConsumed) {
  //                this.mSuccess.invoke(new Object[]{"itemSelected", item.getOrder()});
  //                this.mConsumed = true;
  //                return true;
  //            } else {
  //                return false;
  //            }
  //        }
  //    }
}
